/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bgu.sonar.util.meta;

import bgu.sonar.util.ui.visual.HasVisualData;
import java.awt.Image;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.openide.util.ImageUtilities;

/**
 *
 * @author bennyl
 */
@Target(value = {ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Meta {

    /**
     * if not provided then use the xmlentityname
     *
     * @return
     */
    String displayName() default "";

    String description() default "";

    String icon() default "";

    public static class Support {

        public static Metadata extract(Object o) {
            if (o == null) {
                return null;
            }
            return extractFromClass(o.getClass());
        }

        public static Map<String, Metadata> extractFieldMap(Object o) {
            if (o == null) {
                return Collections.EMPTY_MAP;
            }

            return extractFieldMapFromClass(o.getClass());
        }

        public static Metadata extractFromClass(Class<?> c) {
            return new Metadata(c);
        }

        public static Map<String, Metadata> extractFieldMapFromClass(Class<?> c) {
            Map<String, Metadata> result = new LinkedHashMap<>();
            for (Field f : c.getFields()) {
                if (Modifier.isPublic(f.getModifiers()) && !Modifier.isStatic(f.getModifiers())) {
                    Metadata r = new Metadata(f);
                    result.put(r.getVisualName(), r);
                }
            }

            return result;
        }
    }

    public static class Metadata implements HasVisualData {

        private String name = "";
        private String description = "";
        private Class<?> type;
        private Field field = null;
        private String icon = null;

        public Metadata(Class<?> c) {
            type = c;
            Meta ano = c.getAnnotation(Meta.class);
            if (ano != null) {
                fromAno(ano);
            }

            if (name.isEmpty()) {
                name = camelCaseToSpaceSeperated(c.getSimpleName());
            }
        }

        private static String camelCaseToSpaceSeperated(String s) {
            StringBuilder sb = new StringBuilder();
            char[] schars = s.toCharArray();

            for (char c : schars) {
                if (Character.isUpperCase(c)) {
                    sb.append(' ').append(Character.toLowerCase(c));
                } else {
                    sb.append(c);
                }
            }

            if (sb.charAt(0) == ' ') {
                sb.delete(0, 1);
            }

            return sb.toString();
        }

        public Field getField() {
            return field;
        }

        public Metadata(Field f) {
            type = f.getType();
            field = f;
            Meta ano = f.getAnnotation(Meta.class);
            if (ano != null) {
                fromAno(ano);
            }
            if (name.isEmpty()) {
                name = camelCaseToSpaceSeperated(f.getName());
            }

        }

        public Class<?> getType() {
            return type;
        }

        @Override
        public String getVisualName() {
            return name;
        }

        public String getDescription() {
            return description;
        }

        private void fromAno(Meta ano) {
            description = ano.description();
            name = ano.displayName();
            icon = ano.icon();
            if (icon.isEmpty()) {
                icon = null;
            }
        }

        public String getIconPath() {
            return icon;
        }

        @Override
        public Image getIcon() {
            if (icon == null) {
                return null;
            }
            return ImageUtilities.loadImage(getIconPath());
        }
    }
}
